<!--
 * @Author: your name
 * @Date: 2021-08-09 15:17:05
 * @LastEditTime: 2021-08-09 21:26:20
 * @LastEditors: lmh
 * @Description: 虚拟DOM 
-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="root">
        <div class="tt1" title="sss0">测试1</div>
        <div title="sss1">测试2</div>
        <div title="sss2">测试3</div>
        <div title="sss3">测试4</div>
        <ul>
            <li>排1</li>
            <li>排5</li>
            <li>排3</li>
            <li>排4</li>
            <li>排2</li>
        </ul>
    </div>
</body>
</html>
<script>
    // 为什么使用虚拟DOM? 性能
    class VNode{
        constructor(tag, data, value, type) {
            this.tag = tag?.toLowerCase()
            this.data = data
            this.value = value
            this.type = type
            this.children = []
        }
        appendChild(vnode) {
            this.children.push(vnode)
        }
    }

    // 使用递归 来遍历DOM元素,生成虚拟DOM
    // VUE源码中使用的 栈结构, 使用栈存储 父元素来实现递归生成
    function getVnode(node) {
        let nodeType = node.nodeType
        let _vnode = null
        if (nodeType == 1) { // 元素
            let nodeName = node.nodeName
            let attrs = node.attributes
            let _attrObj = {}
            for(let i = 0; i < attrs.length; i++) {
                _attrObj[attrs[i].nodeName] = attrs[i].nodeValue 
            }
            _vnode = new VNode(nodeName, _attrObj, undefined, nodeType)

            let childNodes = node.childNodes
            for(let i = 0; i < childNodes.length; i++) {
                _vnode.appendChild(getVnode(childNodes[i]))
            } 
        } else if (nodeType == 3) {
            _vnode = new VNode(undefined, undefined, node.nodeValue, nodeType)
        }

        return _vnode
    }

    let root = document.querySelector('#root')
    let vroot = getVnode(root)
    console.log(vroot)

    // 将vNode转换为真正的DOM
    function parseVNode(vnode) {
        let type = vnode.type
        let _node = null
        if (type == 3) {
            return document.createTextNode(vnode.value) // 创建文本节点
        } else if (type == 1) {
            _node = document.createElement(vnode.tag)

            let data = vnode.data
            Object.keys(data).forEach(key => {
                let attrName = key
                let attrValue = data[key]
                _node.setAttribute(attrName, attrValue)
            })

            // 子元素
            let children = vnode.children
            children.forEach(subvnode => {
                _node.appendChild(parseVNode(subvnode)) // 递归转换字元素
            })

            return  _node
        }
    }
    let dom2 = parseVNode(vroot)
    console.log(dom2)
</script>